package edu.cmu.vlis.datamining.TopologicalFeatures;

import java.util.StringTokenizer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.jgrapht.GraphMapping;
import org.jgrapht.graph.ClassBasedEdgeFactory;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.Multigraph;

import edu.cmu.vlis.datamining.core.Edge;
import edu.cmu.vlis.datamining.core.Edge1;
import edu.cmu.vlis.datamining.core.Feature;
import edu.cmu.vlis.datamining.core.IFeatureCalculator;
import edu.cmu.vlis.datamining.core.Vertex;
import edu.cmu.vlis.datamining.core.Vertex1;
import edu.cmu.vlis.datamining.core.Vertex1Comparator;


public class InformationCascadeFeatureExtractor {

	//List<DefaultDirectedWeightedGraph<Integer, Edge1>> cascadePattern = null;
	private DefaultDirectedWeightedGraph<Vertex, Edge> _graph;
	private Multigraph<Vertex, Edge> _trainGraph;
	int number = 1;
	String str=null;
	String strCas= null;
	Map<Vertex ,Set<Integer>> cascadeFList;

	private Feature[] feature;
	DefaultDirectedWeightedGraph<Integer,Edge1> current_g;
	//Training BlogBlog graph vertex map: BlogUrl, Vertex
	Map<String,Vertex> trgGraphVertexMap;
	//Train Post Post Graph PostId vs BlogUrl graph
	Map<Integer,String> trgPostBlogMap;
	//Cascade Map of Cascade Vertex and Post Id
	//Map<Integer,Integer>cascadeVertexNumberMap;
	Map<Integer,Integer>localCascadeVertexNumberMap;

	public InformationCascadeFeatureExtractor(DefaultDirectedWeightedGraph<Vertex, Edge> postGraph,
			Multigraph<Vertex, Edge> blogGraph,
			Map<Integer,String> trgPostBlogMap,
			Map<String,Vertex> trgGraphVertexMap) {
		//cascadePattern = new ArrayList<DefaultDirectedWeightedGraph<Integer, Edge1>>();
		_graph = postGraph;
		_trainGraph = blogGraph;
		//blogMap = new HashMap<String,Integer>();
		cascadeFList = new HashMap<Vertex,Set<Integer>>();

		this.trgGraphVertexMap = trgGraphVertexMap;

		/*Set<String> test = trgGraphVertexMap.keySet();

		for(String st : test) {
			System.out.println(st);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("non");*/

		this.trgPostBlogMap  = trgPostBlogMap;

	}

	public Map<Vertex ,Set<Integer> > ExtractFeatures() {
		int prevNumOfCascades=0;
		System.out.println("Extracting cascade features!");
		String cascadesOut= "";
		try {
			File fId = new File("cascadesId.txt");
			File fcasOut = new File("cascade_out.txt");
			File fcas = new File("cascades.txt");
			File foutCasF = new File("cascadesCas.txt");
			if( !foutCasF.exists()) {
				String distinctCascades = "";

				System.out.println("Extracting cascades!");
				String cascadesAll =  "";
				String cascadesCas = "";
				String distinctCascadesFinal="";
				int maxCor=0;

				if(!fcasOut.exists()){
					try {
						System.out.println("this is irrtating me!");
						FileWriter fout = new FileWriter("cascades.txt");
						BufferedWriter out = new BufferedWriter(fout);
						FileWriter foutCas = new FileWriter("cascadesCas.txt");
						BufferedWriter outCas = new BufferedWriter(foutCas);
						FileWriter foutCasOut = new FileWriter("cascades_out.txt");
						BufferedWriter outCasOut = new BufferedWriter(foutCasOut);
						FileWriter foutId = new FileWriter("cascadeIds.txt");
						BufferedWriter outId = new BufferedWriter(foutId);


						int i=0;
						for(Vertex v: _graph.vertexSet()) {
							str = "";
							strCas = "";
							//check if v is the initiator.
							if(_graph.outDegreeOf(v) == 0 ) {
								localCascadeVertexNumberMap = new HashMap<Integer,Integer>();
								current_g = new DefaultDirectedWeightedGraph<Integer,Edge1>(
										new ClassBasedEdgeFactory<Integer,Edge1>(Edge1.class));					
								localCascadeVertexNumberMap.put(v.getVertexId(),number);
								current_g.addVertex(number);
								number++;
								findCascades(v);
								System.out.println("returned!");
								if(str!=null) {
									str = str + "\n";
									strCas = strCas + "\n";
									cascadesAll = cascadesAll + str;
									cascadesCas = cascadesCas + strCas;
									CascadeReturn cr= new CascadeReturn();

									cr.setNewCascade(distinctCascades + str);
									System.out.println("going into");
									cr = SimpleCascadeEnumeration.runClass(cr);
									System.out.println("From here ");
									distinctCascadesFinal= cr.getDistinctCascade();
									String tmp[] = cr.getId().split("\n");

									int cascadeId = Integer.parseInt(tmp[tmp.length-1]);
									StringTokenizer st = new StringTokenizer(strCas," \n",false);
									while(st.hasMoreTokens()){
										//get the postid of the vertex from cascade number
										String blogUrl = st.nextToken();

										//System.out.println(blogUrl);
										if(trgGraphVertexMap.containsKey(blogUrl)) {
											Vertex vTemp =  trgGraphVertexMap.get(blogUrl);
											/*if(vTemp==null)*/
											// System.out.println(" cascade " + cascadeId + " Ver " + vTemp.getVertexId());
											//Map<Vertex,List<Feature>> vMapFeatures = vTemp.getFeatures();
											Set <Integer> fList=null; 
											if(cascadeFList.containsKey(vTemp)) {
												fList = cascadeFList.get(vTemp);
												//cascadeFList.remove(vTemp);
											}
											else {
												//	System.out.println("does it even contain once??");
												fList = new HashSet<Integer>();
											}
											//Feature f = new Feature(cascadeId,1);
											fList.add(cascadeId);
											//if(fList.size()>23)
											//	 System.out.println("Some things worng id !!" + cascadeId);
											cascadeFList.put(vTemp, fList);
											//vTemp.setFeatures(vTemp, fList);
										}
										else {
											System.out.println("cannot happen + " + blogUrl);
										}
									}
									cascadesOut = cascadesOut + tmp[tmp.length-1] + "\n";
									int nextNumOfCascades =distinctCascadesFinal.split("\n").length;

									/*process distinct cascades in distinct cascades */
									/*by removing type number*/
									if(prevNumOfCascades < nextNumOfCascades) {
										//new cacade added at end
										String [] cascades = distinctCascadesFinal.split("\n");
										String newCascade =cascades[prevNumOfCascades];
										String strTemp[] = newCascade.split(":");
										StringTokenizer st1 = new StringTokenizer(strTemp[1]," ; ->");
										//String newCas = "";
										int newMax = maxCor;
										while(st1.hasMoreTokens()) {
											int number = Integer.parseInt(st1.nextToken());

											number = number + maxCor;
											if(number > maxCor) {
												newMax =number;
											}

											distinctCascades = distinctCascades + number + " ";
										}				
										maxCor= newMax;
										distinctCascades = distinctCascades + "\n";
										prevNumOfCascades++;
									}	
									//Write in file 
									if(i==100) {
										out.write(cascadesAll);
										outCas.write(cascadesCas);
										outCasOut.write(cascadesOut);
										//outId.write(cascadesCas);
										cascadesAll =  "";
										cascadesCas = "";
										cascadesOut= "";
										i=0;
									}
									else
										i++;	
								}
							}
						}

						out.write(cascadesAll);
						outCas.write(cascadesCas);
						outCasOut.write(cascadesOut);
						outId.write(distinctCascadesFinal);
						cascadesAll =  "";
						cascadesCas = "";
						out.close();
						outCas.close();
						outCasOut.close();
						outId.close();
						distinctCascadesFinal = "";
					}
					catch (IOException e) {
						// TODO Auto-generated catch block
						System.out.println( e.toString());
					}	
				}
				str =cascadesCas;
			}
			else {
				str ="";
				cascadesOut ="";
				try {
					FileReader fin = new FileReader("cascadesCas.txt");
					BufferedReader in = new BufferedReader(fin);
					String line= null;
					int i =0;
					while((line = in.readLine())!=null) {
						if(str =="")
							str =line;
						else
							str = str + "\n" + line;
						i++;
					}
					System.out.println("am i done11??");
					in.close();
					FileReader fin1 = new FileReader("cascades_out.txt");
					BufferedReader in1 = new BufferedReader(fin1);
					String line1 = null;
					while((line1=in1.readLine())!=null) {
						if(cascadesOut==null ||cascadesOut=="" )
							cascadesOut = line1;
						else
							cascadesOut = cascadesOut + "\n"; 
					}
					in1.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					System.out.println("here" + e.toString());
				}		
				System.out.println("**********Completed parsing the graph to identify the cascades");
				Thread.sleep(5000);
				System.out.println("Strating with building feature Vector");

				//Construct the features vector
				String[] str1 = str.split("\n");

				String[] cascades =cascadesOut.split("\n");
				int i=0;
				int length = str1.length;
				while(i<length) {	
					if( (i%1000) ==0) {
						System.out.println( i + " cascades completed!");
					}
					int cascadeId= Integer.parseInt(cascades[i]);
					StringTokenizer st = new StringTokenizer(str1[i]," \n",false);
					while(st.hasMoreTokens()){
						//get the postid of the vertex from cascade number
						String blogUrl = st.nextToken();
						Vertex v =  trgGraphVertexMap.get(blogUrl);
						Set <Integer> fList=null; 
						if(cascadeFList.containsKey(v)) {
							fList = cascadeFList.get(v);
							cascadeFList.remove(v);
						}
						else {

							fList = new HashSet<Integer>();
						}
						Feature f = new Feature(cascadeId,1);
						fList.add(cascadeId);
						cascadeFList.put(v, fList);

					}
					i++;
				}
			}
		}catch(Exception e) {
			System.out.println(e.toString());
		}
		return cascadeFList;
	}



	public void findCascades(Vertex v) {
		System.out.println("in fc");
		try {
			for(Edge e : _graph.incomingEdgesOf(v)) { 
				int newV1=0;
				Vertex v1 = _graph.getEdgeSource(e);
				if(v!=v1) {
					if(localCascadeVertexNumberMap.containsKey(v1.getVertexId())) {
						//System.out.println("At least one repeated!");
						newV1 = localCascadeVertexNumberMap.get(v1.getVertexId());	
						str = str + localCascadeVertexNumberMap.get(v.getVertexId()) + " " +newV1 + " ";
						strCas = strCas + (v.getSupplementaryUrl()) + " " + v1.getSupplementaryUrl() + " ";
					}
					else {
						newV1 = number;
						localCascadeVertexNumberMap.put(v1.getVertexId(),newV1);
						//vertexBlogNoMap.put(newV1, trgGraphVertexMap.get(v1.getSupplementaryUrl()).getVertexId());
						number++;
						current_g.addVertex(newV1);
						current_g.addEdge(newV1,localCascadeVertexNumberMap.get(v.getVertexId()));
						str = str + localCascadeVertexNumberMap.get(v.getVertexId()) + " " +newV1 + " ";
						strCas = strCas + (v.getSupplementaryUrl()) + " " + v1.getSupplementaryUrl() + " ";
						findCascades(v1);
					}

				}		
			} 


		}catch(Exception e) {
			System.out.println(e.toString());
		}

	}
}
